/* ------------------------------------------------------------------------
 *
 * nodeCustom.c
 *		处理自定义扫描节点执行的例程
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * ------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/parallel.h"
#include "executor/executor.h"
#include "executor/nodeCustom.h"
#include "miscadmin.h"
#include "nodes/execnodes.h"
#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "parser/parsetree.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "utils/rel.h"

static TupleTableSlot *fc_ExecCustomScan(PlanState *fc_pstate);


CustomScanState *
ExecInitCustomScan(CustomScan *fc_cscan, EState *fc_estate, int fc_eflags)
{
	CustomScanState *fc_css;
	Relation	fc_scan_rel = NULL;
	Index		fc_scanrelid = fc_cscan->scan.scanrelid;
	int			fc_tlistvarno;

	/*
	 * 分配CustomScanState对象。我们让自定义扫描提供者
	 * 进行palloc，以便它想要创建一个更大的对象，将
	 * CustomScanState嵌入为第一个字段。它必须在此时
	 * 正确设置节点标签和方法字段。其他标准字段应设置为零。
	 */
	fc_css = castNode(CustomScanState,
				   fc_cscan->methods->CreateCustomScanState(fc_cscan));

	/* 确保标志正确填写 */
	fc_css->flags = fc_cscan->flags;

	/* 填充ScanState的字段 */
	fc_css->ss.ps.plan = &fc_cscan->scan.plan;
	fc_css->ss.ps.state = fc_estate;
	fc_css->ss.ps.ExecProcNode = fc_ExecCustomScan;

	/* 为节点创建表达式上下文 */
	ExecAssignExprContext(fc_estate, &fc_css->ss.ps);

	/*
	 * 打开扫描关系（如果有的话）
	 */
	if (fc_scanrelid > 0)
	{
		fc_scan_rel = ExecOpenScanRelation(fc_estate, fc_scanrelid, fc_eflags);
		fc_css->ss.ss_currentRelation = fc_scan_rel;
	}

	/*
	 * 确定扫描元组类型。如果自定义扫描提供者提供了
	 * 描述扫描元组的目标列表，则使用该列表；否则使用基础
	 * 关系的行类型。
	 */
	if (fc_cscan->custom_scan_tlist != NIL || fc_scan_rel == NULL)
	{
		TupleDesc	fc_scan_tupdesc;

		fc_scan_tupdesc = ExecTypeFromTL(fc_cscan->custom_scan_tlist);
		ExecInitScanTupleSlot(fc_estate, &fc_css->ss, fc_scan_tupdesc, &TTSOpsVirtual);
		/* 节点的目标列表将包含varno = INDEX_VAR的Vars */
		fc_tlistvarno = INDEX_VAR;
	}
	else
	{
		ExecInitScanTupleSlot(fc_estate, &fc_css->ss, RelationGetDescr(fc_scan_rel),
							  &TTSOpsVirtual);
		/* 节点的目标列表将包含varno = scanrelid的Vars */
		fc_tlistvarno = fc_scanrelid;
	}

	/*
	 * 初始化结果槽、类型和投影。
	 */
	ExecInitResultTupleSlotTL(&fc_css->ss.ps, &TTSOpsVirtual);
	ExecAssignScanProjectionInfoWithVarno(&fc_css->ss, fc_tlistvarno);

	/* 初始化子表达式 */
	fc_css->ss.ps.qual =
		ExecInitQual(fc_cscan->scan.plan.qual, (PlanState *) fc_css);

	/*
	 * 自定义扫描提供者的回调根据其逻辑应用
	 * 自定义扫描状态节点的最终初始化。
	 */
	fc_css->methods->BeginCustomScan(fc_css, fc_estate, fc_eflags);

	return fc_css;
}

static TupleTableSlot * fc_ExecCustomScan(PlanState *fc_pstate)
{
	CustomScanState *fc_node = castNode(CustomScanState, fc_pstate);

	CHECK_FOR_INTERRUPTS();

	Assert(fc_node->methods->ExecCustomScan != NULL);
	return fc_node->methods->ExecCustomScan(fc_node);
}

void ExecEndCustomScan(CustomScanState *fc_node)
{
	Assert(fc_node->methods->EndCustomScan != NULL);
	fc_node->methods->EndCustomScan(fc_node);

	/* 释放 exprcontext */
	ExecFreeExprContext(&fc_node->ss.ps);

	/* 清空元组表 */
	ExecClearTuple(fc_node->ss.ps.ps_ResultTupleSlot);
	ExecClearTuple(fc_node->ss.ss_ScanTupleSlot);
}

void ExecReScanCustomScan(CustomScanState *fc_node)
{
	Assert(fc_node->methods->ReScanCustomScan != NULL);
	fc_node->methods->ReScanCustomScan(fc_node);
}

void ExecCustomMarkPos(CustomScanState *fc_node)
{
	if (!fc_node->methods->MarkPosCustomScan)
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("custom scan \"%s\" does not support MarkPos",
						fc_node->methods->CustomName)));
	fc_node->methods->MarkPosCustomScan(fc_node);
}

void ExecCustomRestrPos(CustomScanState *fc_node)
{
	if (!fc_node->methods->RestrPosCustomScan)
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("custom scan \"%s\" does not support MarkPos",
						fc_node->methods->CustomName)));
	fc_node->methods->RestrPosCustomScan(fc_node);
}

void ExecCustomScanEstimate(CustomScanState *fc_node, ParallelContext *fc_pcxt)
{
	const CustomExecMethods *fc_methods = fc_node->methods;

	if (fc_methods->EstimateDSMCustomScan)
	{
		fc_node->pscan_len = fc_methods->EstimateDSMCustomScan(fc_node, fc_pcxt);
		shm_toc_estimate_chunk(&fc_pcxt->estimator, fc_node->pscan_len);
		shm_toc_estimate_keys(&fc_pcxt->estimator, 1);
	}
}

void ExecCustomScanInitializeDSM(CustomScanState *fc_node, ParallelContext *fc_pcxt)
{
	const CustomExecMethods *fc_methods = fc_node->methods;

	if (fc_methods->InitializeDSMCustomScan)
	{
		int			fc_plan_node_id = fc_node->ss.ps.plan->plan_node_id;
		void	   *fc_coordinate;

		fc_coordinate = shm_toc_allocate(fc_pcxt->toc, fc_node->pscan_len);
		fc_methods->InitializeDSMCustomScan(fc_node, fc_pcxt, fc_coordinate);
		shm_toc_insert(fc_pcxt->toc, fc_plan_node_id, fc_coordinate);
	}
}

void ExecCustomScanReInitializeDSM(CustomScanState *fc_node, ParallelContext *fc_pcxt)
{
	const CustomExecMethods *fc_methods = fc_node->methods;

	if (fc_methods->ReInitializeDSMCustomScan)
	{
		int			fc_plan_node_id = fc_node->ss.ps.plan->plan_node_id;
		void	   *fc_coordinate;

		fc_coordinate = shm_toc_lookup(fc_pcxt->toc, fc_plan_node_id, false);
		fc_methods->ReInitializeDSMCustomScan(fc_node, fc_pcxt, fc_coordinate);
	}
}

void ExecCustomScanInitializeWorker(CustomScanState *fc_node,
							   ParallelWorkerContext *fc_pwcxt)
{
	const CustomExecMethods *fc_methods = fc_node->methods;

	if (fc_methods->InitializeWorkerCustomScan)
	{
		int			fc_plan_node_id = fc_node->ss.ps.plan->plan_node_id;
		void	   *fc_coordinate;

		fc_coordinate = shm_toc_lookup(fc_pwcxt->toc, fc_plan_node_id, false);
		fc_methods->InitializeWorkerCustomScan(fc_node, fc_pwcxt->toc, fc_coordinate);
	}
}

void ExecShutdownCustomScan(CustomScanState *fc_node)
{
	const CustomExecMethods *fc_methods = fc_node->methods;

	if (fc_methods->ShutdownCustomScan)
		fc_methods->ShutdownCustomScan(fc_node);
}
